import 'dart:async';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:get/get.dart';
import 'package:logger/logger.dart';
import 'package:mziot/app/config/design.dart';
import 'package:mziot/app/tools/blue_service.dart';
import 'package:mziot/app/tools/device.dart';
import 'package:mziot/generated/locales.g.dart';
import 'package:permission_handler/permission_handler.dart';

showToast(String message) {
  Fluttertoast.showToast(msg: message, gravity: ToastGravity.CENTER, timeInSecForIosWeb: 2);
}

var logger = Logger(
  printer: PrettyPrinter(methodCount: 1),
);

var loggerNoStack = Logger(
  printer: PrettyPrinter(methodCount: 0),
);

var loadingWidget = SpinKitCircle(
  color: Colors.white,
  size: 20.0,
);

// 节流函数
const deFaultDurationTime = 1000;
Timer? timer;

const String deFaultThrottleId = 'DeFaultThrottleId';
Map<String, int> startTimeMap = {deFaultThrottleId: 0};
throttle(Function doSomething,
    {String throttleId = deFaultThrottleId, durationTime = deFaultDurationTime}) {
  int currentTime = DateTime.now().millisecondsSinceEpoch;
  if (currentTime - (startTimeMap[throttleId] ?? 0) > durationTime) {
    doSomething.call();
    startTimeMap[throttleId] = DateTime.now().millisecondsSinceEpoch;
  }
}

mzdebounce(Function doSomething, {durationTime = deFaultDurationTime}) {
  timer?.cancel();
  timer = Timer(Duration(milliseconds: durationTime), () {
    doSomething.call();
    timer = null;
  });
}

class MPermission {
  static MPermission instance = MPermission();

  Future<bool> bluetooth() async {
    if (Platform.isAndroid) {
      final version = double.parse(DeviceUtils.sysVersion ?? '0');
      if (version >= 12) {
        PermissionStatus scanStatus = await Permission.bluetoothScan.status;
        PermissionStatus advertiseStatus = await Permission.bluetoothAdvertise.status;
        PermissionStatus connectStatus = await Permission.bluetoothConnect.status;
        switch (scanStatus) {
          case PermissionStatus.denied:
            final temp = await Permission.bluetoothScan.request();
            if (temp.isPermanentlyDenied || temp.isDenied) {
              showCustomDialog(
                LocaleKeys.tips_ble_scan.tr,
                cancel: true,
                onConfirm: () => openAppSettings(),
              );
            }
            return Future.value(temp.isGranted);
          case PermissionStatus.permanentlyDenied:
            showCustomDialog(
              LocaleKeys.tips_ble_scan.tr,
              cancel: true,
              onConfirm: () => openAppSettings(),
            );
            return Future.value(false);
        }

        switch (connectStatus) {
          case PermissionStatus.denied:
            final temp = await Permission.bluetoothConnect.request();
            if (temp.isPermanentlyDenied || temp.isDenied) {
              showCustomDialog(
                LocaleKeys.tips_ble_per.tr,
                cancel: true,
                onConfirm: () => openAppSettings(),
              );
            }
            return Future.value(temp.isGranted);
          case PermissionStatus.permanentlyDenied:
            showCustomDialog(
              LocaleKeys.tips_ble_per.tr,
              cancel: true,
              onConfirm: () => openAppSettings(),
            );
            return Future.value(false);
        }

        switch (advertiseStatus) {
          case PermissionStatus.denied:
            final temp = await Permission.bluetoothAdvertise.request();
            if (temp.isPermanentlyDenied || temp.isDenied) {
              showCustomDialog(
                LocaleKeys.tips_ble_notify.tr,
                cancel: true,
                onConfirm: () => openAppSettings(),
              );
            }
            return Future.value(temp.isGranted);
          case PermissionStatus.permanentlyDenied:
            showCustomDialog(
              LocaleKeys.tips_ble_notify.tr,
              cancel: true,
              onConfirm: () => openAppSettings(),
            );
            return Future.value(false);
        }
      } else {
        PermissionStatus location = await Permission.location.status;
        PermissionStatus status = await Permission.bluetooth.status;

        switch (location) {
          case PermissionStatus.denied:
            final temp = await Permission.location.request();
            if (temp.isPermanentlyDenied) {
              showCustomDialog(
                LocaleKeys.tips_ble_per.tr,
                cancel: true,
                onConfirm: () => openAppSettings(),
              );
            }
            return Future.value(temp.isGranted);
          case PermissionStatus.permanentlyDenied:
            showCustomDialog(
              LocaleKeys.tips_ble_location.tr,
              cancel: true,
              onConfirm: () => openAppSettings(),
            );
            return Future.value(false);
        }

        switch (status) {
          case PermissionStatus.denied:
            final temp = await Permission.bluetooth.request();
            if (temp.isPermanentlyDenied || temp.isDenied) {
              showCustomDialog(
                LocaleKeys.tips_ble_per.tr,
                cancel: true,
                onConfirm: () => openAppSettings(),
              );
            }
            return Future.value(temp.isGranted);
          case PermissionStatus.permanentlyDenied:
            final temp = await Permission.bluetooth.request();
            if (temp.isPermanentlyDenied || temp.isDenied) {
              showCustomDialog(
                LocaleKeys.tips_ble_per.tr,
                cancel: true,
                onConfirm: () => openAppSettings(),
              );
            }
            return Future.value(temp.isGranted);
        }
      }
    } else {
      PermissionStatus status = await Permission.bluetooth.status;
      switch (status) {
        case PermissionStatus.restricted:
          final temp = await Permission.bluetooth.request();
          return Future.value(temp.isGranted);
        case PermissionStatus.denied:
          showCustomDialog(
            LocaleKeys.tips_ble_per.tr,
            cancel: true,
            onConfirm: () => openAppSettings(),
          );
          return Future.value(false);
        case PermissionStatus.limited:
          showCustomDialog(
            LocaleKeys.tips_ble_per.tr,
            cancel: true,
            onConfirm: () => openAppSettings(),
          );
          return Future.value(false);
        case PermissionStatus.permanentlyDenied:
          showCustomDialog(
            LocaleKeys.tips_ble_per.tr,
            cancel: true,
            onConfirm: () => openAppSettings(),
          );
          return Future.value(false);
      }
    }

    final state = BlueService.share.flutterBlue.status;
    if (state == BleStatus.unsupported) {
      showCustomDialog(LocaleKeys.tips_ble_unsurport.tr);
      return Future.value(false);
    }

    if (state != BleStatus.ready) {
      showCustomDialog(LocaleKeys.tips_ble_close.tr);
      return Future.value(false);
    }

    return Future.value(true);
  }
}

showCustomDialog(String text, {VoidCallback? onConfirm, bool cancel = false}) {
  Get.generalDialog(pageBuilder: (ctx, a, s) {
    return CupertinoAlertDialog(
      content: Text(
        text,
        style: MFont.semi_Bold17.apply(color: MColor.xFF333333),
      ),
      actions: <Widget>[
        if (cancel) ...{
          TextButton(
            onPressed: () {
              Get.back();
            },
            child: Text(
              LocaleKeys.devices_cancel.tr,
              style: MFont.regular17.apply(color: MColor.xFF333333),
            ),
          ),
        },
        TextButton(
          onPressed: () {
            if (onConfirm != null) {
              onConfirm();
            }
            Get.back();
          },
          child: Text(
            LocaleKeys.public_ok.tr,
            style: MFont.semi_Bold17.apply(color: MColor.xFF333333),
          ),
        ),
      ],
    );
  });
}

extension Ratio on double {
  double get pixRatio {
    return this * (Get.width / 375.0);
  }
}

/// 防止文字自动换行
extension FixAutoLines on String {
  String fixAutoLines() {
    return Characters(this).join('\u{200B}');
  }
}
